package com.vshop.utils;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;

@Slf4j
public class HMACSHA1_bak {

    private static final String MAC_NAME = "HmacSHA1";
    private static final String ENCODING = "UTF-8";

    public static String generateSign(String data, String secretKey) {
        try {
            SecretKeySpec sk = new SecretKeySpec(secretKey.getBytes("UTF-8"), MAC_NAME);
            Mac mac = Mac.getInstance(MAC_NAME);
            mac.init(sk);
            byte[] res = mac.doFinal(data.getBytes(ENCODING));
            java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
            return encoder.encodeToString(res);
        } catch (Exception e) {
            log.info("HMACSHA1签名异常：" + e);
            return null;
        }

    }

    /**
     * 计算返回报文签名 for json
     */
    public static String jsonSign(Object obj, String key) {
        Map<String, Object> map = dealMap(obj);
        //去掉添加的签名字段
        map.remove("sign");
        map = sortMapByKey(map);
        String headJson = JSON.toJSONString(map);
        String sign = generateSign(headJson, key);
        log.info("HMACSHA1签名体：" + headJson + ";计算签名：" + sign);
        return sign;
    }

    /**
     * 使用 Map按key进行排序
     *
     * @param map
     * @return
     */
    public static Map<String, Object> sortMapByKey(Map<String, Object> map) {

        if (map == null || map.isEmpty()) {
            return null;
        }
        Map<String, Object> sortMap = new TreeMap<String, Object>(new MapKeyComparator());
        sortMap.putAll(map);
        return sortMap;
    }

    /**
     * 将bean转换为map、并处理掉map中的null值，""值
     */
    private static Map<String, Object> dealMap(Object o) {
        Map<String, String> map = new HashMap<String, String>(16);
        try {
            map = BeanUtils.describe(o);
            //避免bean转map后多处class可以的签名，导致请求方的签名与这里签名的不一致
            map.put("class", null);
        } catch (Exception e) {
            log.error("根据传入的实体类生成签名sign发送异常：{}", e);
        }
        Set set = map.keySet();
        for (Iterator iterator = set.iterator(); iterator.hasNext(); ) {
            Object obj = iterator.next();
            Object value = map.get(obj);
            remove(value, iterator);
        }
        Map tm = map;
        return new HashMap<String, Object>(tm);
    }

    /**
     * 移除map中的空值
     * Iterator 是工作在一个独立的线程中，并且拥有一个 mutex 锁。
     * Iterator 被创建之后会建立一个指向原来对象的单链索引表，当原来的对象数量发生变化时，这个索引表的内容不会同步改变，
     * 所以当索引指针往后移动的时候就找不到要迭代的对象，所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
     * 所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。
     * 但你可以使用 Iterator 本身的方法 remove() 来删除对象， Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
     *
     * @param obj
     * @param iterator
     */
    private static void remove(Object obj, Iterator iterator) {
        if (obj instanceof String) {
            if (obj == null || obj.toString().length() == 0) {
                iterator.remove();
            }
        } else if (obj instanceof Collection) {
            Collection col = (Collection) obj;
            if (col == null || col.isEmpty()) {
                iterator.remove();
            }
        } else if (obj instanceof Map) {
            Map temp = (Map) obj;
            if (temp == null || temp.isEmpty()) {
                iterator.remove();
            }
        } else if (obj instanceof Object[]) {
            Object[] array = (Object[]) obj;
            if (array == null || array.length <= 0) {
                iterator.remove();
            }
        } else {
            if (obj == null) {
                iterator.remove();
            }
        }
    }

}
